<template>
    <el-form :model="model" ref="formRef" v-bind="$attrs">
        <template v-for="item in fileds">
            <!-- 输入框 -->
            <template v-if="isShow(item.show, model)">
                <el-form-item v-if="item.type === 'input'" :label="item.label" :prop="item.key"
                    :label-width="item.labelWidth">
                    <el-input v-model="model[item.key]" :placeholder="item.placeholder"></el-input>
                </el-form-item>
            </template>
            <!-- 数字输入框 -->
            <template v-if="isShow(item.show, model)">
                <el-form-item v-if="item.type === 'inputNumber'" :label="item.label" :prop="item.key"
                    :label-width="item.labelWidth">
                    <el-input-number v-model="model[item.key]" :placeholder="item.placeholder"></el-input-number>
                </el-form-item>
            </template>
            <!-- 密码输入框 -->
            <template v-if="isShow(item.show, model)">
                <el-form-item v-if="item.type === 'password'" :label="item.label" :prop="item.key"
                    :label-width="item.labelWidth">
                    <el-input v-model="model[item.key]" type="password" autocomplete="off"
                        :placeholder="item.placeholder"></el-input>
                </el-form-item>
            </template>
            <!-- 下拉框 -->
            <template v-if="isShow(item.show, model)">
                <el-form-item v-if="item.type === 'select'" :label="item.label" :prop="item.key"
                    :label-width="item.labelWidth">
                    <el-select clearable :multiple="item.multiple" v-model="model[item.key]"
                        :placeholder="item.placeholder">
                        <el-option v-for="ele in item.option" :label="ele.label" :value="ele.value" />
                    </el-select>
                </el-form-item>
            </template>
            <!-- 树形下拉框 -->
            <template v-if="isShow(item.show, model)">
                <el-form-item v-if="item.type === 'treeSelect'" :label="item.label" :prop="item.key"
                    :label-width="item.labelWidth">
                    <el-input @click="treeVisible = true" v-model="model[item.key]" readonly
                        :placeholder="item.placeholder"></el-input>
                    <div v-if="treeVisible" class="suspension" v-click-outside="close">
                        <el-tree :current-node-key="model[item.key]" :highlight-current="true" :expand-on-click-node="false"
                            :data="item.option" node-key="_id" :props="defaultProps" @node-click="(node: any) => {
                                model[item.key] = node._id
                                treeVisible = false
                            }" />
                    </div>
                </el-form-item>
            </template>
            <!-- 树 -->
            <template v-if="isShow(item.show, model)">
                <el-form-item v-if="item.type === 'tree'" :label="item.label" :prop="item.key"
                    :label-width="item.labelWidth">
                    <div class="treeView scrollbar">
                        <el-tree ref="treeRefSymbol" show-checkbox :highlight-current="true" :expand-on-click-node="false"
                            :data="item.option" node-key="_id" :props="defaultProps" @node-click="item.nodeClick" />
                    </div>
                </el-form-item>
            </template>
            <!-- 图标下拉 -->
            <template v-if="isShow(item.show, model)">
                <el-form-item v-if="item.type === 'icon'" :label="item.label" :prop="item.key"
                    :label-width="item.labelWidth">
                    <el-input clearable @click="iconVisible = true" v-model="model[item.key]" readonly
                        :placeholder="item.placeholder"></el-input>
                    <div v-if="iconVisible" class="suspension scrollbar" v-click-outside="close">
                        <svg-icon v-for="icon in iconList.glyphs" :key="icon.icon_id" :name="icon.font_class" @click="() => {
                            model[item.key] = icon.font_class
                            iconVisible = false
                        }"></svg-icon>
                    </div>
                </el-form-item>
            </template>
            <!-- 单选框 -->
            <template v-if="isShow(item.show, model)">
                <el-form-item v-if="item.type === 'radio'" :label="item.label" :prop="item.key"
                    :label-width="item.labelWidth">
                    <el-radio-group v-model="model[item.key]" @change="item.change">
                        <el-radio v-for="ele in item.option" :label="ele.value">{{ ele.label }}</el-radio>
                    </el-radio-group>
                </el-form-item>
            </template>
            <!-- 日期选择 -->
            <template v-if="isShow(item.show, model)">
                <el-form-item v-if="item.type === 'date'" :label="item.label" :prop="item.key"
                    :label-width="item.labelWidth">
                    <el-date-picker clearable v-model="model[item.key]" type="date" :placeholder="item.placeholder"
                        format="YYYY/MM/DD" value-format="YYYY-MM-DD" />
                </el-form-item>
            </template>
            <!-- 头像上传 -->
            <template v-if="isShow(item.show, model)">
                <el-form-item v-if="item.type === 'upload'" :label="item.label" :prop="item.key"
                    :label-width="item.labelWidth">
                    <Upload style="font-size: 30px;" ref="uploadRef" :src="model[item.key]" @upload="item.change" :multiple="false" />
                </el-form-item>
            </template>
        </template>
        <el-form-item class="submit">
            <el-button v-if="!option || option?.btnList.includes('reset')" :type="option?.resetType || 'default'"
                @click="resetForm(formRef)">
                {{ option?.resetText || "重 置" }}
            </el-button>
            <el-button v-if="!option || option.btnList.includes('cancel')" :type="option?.cancelType || 'default'"
                @click="cancel">
                {{ option?.cancelText || "取 消" }}
            </el-button>
            <el-button v-if="!option || option.btnList.includes('submit')" :type="option?.submitType || 'primary'"
                @click="submitForm(formRef)">
                {{ option?.submitText || "确 认" }}
            </el-button>
            <slot name="action"></slot>
        </el-form-item>
    </el-form>
</template>

<script lang='ts' setup>
import { ref, } from 'vue';
import { Form } from "@/types/form"
import { FormInstance, ClickOutside as vClickOutside, ElTree } from 'element-plus';
import iconList from "@/assets/iconfont/systemicon/iconfont.json"
import { TreeKey } from 'element-plus/es/components/tree/src/tree.type';
import Upload from "@/components/Action/upload/index.vue"

interface FormProps {
    model: Record<string, any>
    fileds: Form.Fileds[]
    option?: Form.Options
}


let formRef = ref<FormInstance>()

const props = defineProps<FormProps>()

interface FormEmits {
    (e: 'submit', data: any): void
    (e: 'cancel'): void
    (e: 'reset'): void
}

const emits = defineEmits<FormEmits>()


let treeVisible = ref<boolean>(false)
// 监听元素点击外部DOM得事件
const close = () => {
    treeVisible.value = false
    iconVisible.value = false
}

let iconVisible = ref<boolean>(false)
const cancel = () => {
    emits("cancel")
}
// 重置
const resetForm = (formEl?: FormInstance) => {
    if (!formEl) return
    formEl.resetFields()
    uploadRef.value[0].clearFile()
    emits("reset")
}
// 提交
const submitForm = async (formEl?: FormInstance) => {
    if (!formEl) return
    await formEl.validate((valid, fields) => {
        if (!valid) return;
        emits("submit", props.model)
    })
}

const defaultProps = {
    children: 'children',
    label: 'name'
}

const isShow = (show: Form.Show | undefined, model: Record<string, any>) => {
    return typeof show === "boolean" ? show : typeof show === "function" ? show(model) : true
}

let treeRefSymbol = ref()
// 默认选中
const setCheckedKeys = (ids: string[]) => {
    treeRefSymbol.value![0].setCheckedKeys(ids, false)
}
// 获取选中的数据id
const getCheckedKeys = (): TreeKey[] => {

    // 目前被选中的菜单节点
    let checkedKeys = treeRefSymbol.value![0].getCheckedKeys();
    // 半选中的菜单节点
    let halfCheckedKeys = treeRefSymbol.value![0].getHalfCheckedKeys();

    return [...halfCheckedKeys, ...checkedKeys]
}
// 重置
const resetChecked = () => {
    treeRefSymbol.value![0].setCheckedKeys([], false)

}

let uploadRef = ref()

defineExpose({
    setCheckedKeys,
    getCheckedKeys,
    resetChecked,
})

</script>

<style lang="less" scoped>
.suspension {
    width: 100%;
    max-height: 350px;
    overflow: auto;
    position: absolute;
    top: 45px;
    background-color: var(--background);
    z-index: 3;
    box-shadow: var(--shadowColor) 0px 2px 8px;
    border-radius: 5px;
    padding: 10px;
    transition: all .3s;

    .el-tree {
        width: 100%;
    }

    .svg-icon {
        font-size: 24px;

        &:hover {
            transform: scale(2);
        }
    }
}

.treeView {
    width: 100%;
    height: auto;
    max-height: 400px;
    overflow-y: auto;

    :deep(.el-checkbox) {
        margin-bottom: 0px !important;
    }
}
</style>